home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / MATRIX.ZIP / SOURCE.ZIP / MATRIX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-13  |  25.6 KB  |  882 lines

  1. /*
  2.  *
  3.  *  MATRIX.C
  4.  *
  5.  *  (Simon Hern, August 1993 - June 1995)
  6.  *
  7.  *  Matrix demo - animation of viewer gliding above an infinite tiled floor (!)
  8.  *
  9.  *  Uses graphics routines in MTXCODE.ASM and table in ANGSINES.ASM
  10.  *
  11.  */
  12.  
  13. #include <stdlib.h>
  14. #include <time.h>
  15. #include <conio.h>
  16. #include <fcntl.h>
  17. #include <dos.h>
  18. #include <math.h>
  19. #include <string.h>
  20. #include <alloc.h>
  21.  
  22.  
  23.  
  24. /* CONSTANT DEFINITIONS */
  25.  
  26. #define PI 3.141592654L
  27.  
  28. /* Number of possible directions to move/look in */
  29. #define ANGLES 1024L
  30.  
  31. /* Screen dimensions */
  32. #define SCR_HEIGHT 200L
  33. #define SCR_WIDTH 320L
  34.  
  35. /* Viewer's perspective - distance of virtual eye from screen (pixels) */
  36. #define VIEW_DIST 512L
  37.  
  38. /* Number of bytes used for tile image (one full segment!)    */
  39. /* (This size is to save having to clip coordinate variables  */
  40. /*  - just use 8 bit variables. Bit of a waste of memory tho) */
  41. #define TILE_SIZE 256L*256L
  42.  
  43.  
  44.  
  45. /* STRUCTURE DECLARATIONS */
  46.  
  47. /* Structure for holding one palette setting */
  48. typedef struct {
  49.     char red;
  50.     char green;
  51.     char blue;
  52. } RGBvals;
  53.  
  54.  
  55.  
  56. /* Structure associating names with predefined colours */
  57. typedef struct {
  58.     char * name;
  59.     RGBvals colour;
  60. } NamedColour;
  61.  
  62. #define COLOURS 21
  63.  
  64. NamedColour Colours[COLOURS] = {
  65.     { "black", { 0, 0, 0 } },
  66.     { "blue", { 0, 0, 63 } },          { "darkblue", { 0, 0, 31 } },
  67.     { "red", { 63, 0, 0 } },           { "darkred", { 31, 0, 0 } },
  68.     { "magenta", { 63, 0, 63 } },      { "darkmagenta", { 31, 0, 31 } },
  69.     { "green", { 0, 63, 0 } },         { "darkgreen", { 0, 31, 0 } },
  70.     { "cyan", { 0, 63, 63 } },         { "darkcyan", { 0, 31, 31 } },
  71.     { "yellow", { 63, 63, 0 } },       { "darkyellow", { 31, 31, 0 } },
  72.     { "white", { 63, 63, 63 } },
  73.     { "orange", { 63, 31, 0 } },       { "darkorange", { 31, 15, 0 } },
  74.     { "pink", { 63, 0, 31 } },         { "darkpink", { 31, 0, 15 } },
  75.     { "violet", { 47, 0, 63 } },
  76.     { "turquoise", { 0, 63, 31 } },
  77.     { "grey", { 31, 31, 31 } }
  78. };
  79.  
  80.  
  81.  
  82. /* Structure for predefined colour sets - named colours, one for the sky */
  83. /*  and two for the tiles                                                */
  84. typedef struct {
  85.     char * tile1;
  86.     char * tile2;
  87.     char * sky;
  88. } ColourSet;
  89.  
  90. #define COLOUR_CHOICES 8
  91.  
  92. ColourSet ScreenColours[COLOUR_CHOICES] = {
  93.     { "red", "blue", "cyan" },
  94.     { "green", "blue", "darkyellow" },
  95.     { "orange", "black", "darkmagenta" },
  96.     { "white", "blue", "violet" },
  97.     { "black", "white", "blue" },
  98.     { "yellow", "violet", "grey" },
  99.     { "grey", "darkred", "orange" },
  100.     { "yellow", "blue", "darkgreen" },
  101. };
  102.  
  103.  
  104.  
  105. /* FUNCTION DECLARATIONS */
  106.  
  107. int Animate();
  108. void MoveMatrix();
  109. void PaintSky();
  110. void PaintTile();
  111. int LoadTile(char * fname);
  112. void BlurPalette();
  113. void GoBlack();
  114.  
  115. void Message();
  116. void Error(char * comment);
  117.  
  118. void AllocateMemory();
  119. void FreeMemory();
  120.  
  121. void MakeDistances();
  122. void MakeBlurs();
  123.  
  124. void CommandArguments(int argc, char * argv[]);
  125. void ChooseColours();
  126.  
  127. char * ReadColour(RGBvals * dest, char * str);
  128. void ListSkyColours(char * dest);
  129. void ListTileColours(char * dest);
  130.  
  131. float Sin(int a);
  132. float Cos(int a);
  133.  
  134.  
  135.  
  136. /* EXTERNAL (ASSEMBLER) FUNCTIONS */
  137.  
  138. /* ScreenOn: mode 13h - 320*200 in 256 colours */
  139. extern void ScreenOn(void);
  140.  
  141. /* ScreenOff: text mode */
  142. extern void ScreenOff(void);
  143.  
  144. /* SetPalette: set some or all of palette */
  145. extern void SetPalette(RGBvals near *, int start, int number);
  146.  
  147. /* DisplayMatrix: draw Matrix in bottom half of screen */
  148. extern void DisplayMatrix(int angle, int xpos, int ypos);
  149.  
  150. extern int AngleSines[ANGLES];
  151.  
  152.  
  153.  
  154. /* GLOBAL VARIABLES */
  155.  
  156. char far * Tile;  /* Pointer to tile image (must start on segment boundary */
  157. char far * ScrBuffer;  /* Screen buffer for animated part of screen */
  158. int * Distances;  /* Array of precalculated values, one for each line drawn */
  159. unsigned char * Blurs;  /* Array of 'blur' factors for fading near horizon */
  160. RGBvals * Palette;  /* Complete 256 value palette to be used */
  161.  
  162. char far * Tile_alloc;       /* Start of areas of memory allocated for Tile, */
  163. char far * ScrBuffer_alloc;  /*  ScrBuffer and Distances arrays. An overlap  */
  164. char * Distances_alloc;      /*  is allowed for aligning with segment bounds */
  165.  
  166.  
  167. RGBvals SkyColour = { -1, -1, -1 };  /* Brightest colour in the sky */
  168. int DullSky;  /* Flag: sky fades up slowly, never reaches full brightness */
  169.  
  170. RGBvals TileColour1 = { -1, -1, -1 };  /* Colour at middle of tile */
  171. RGBvals TileColour2 = { -1, -1, -1 };  /* Colour at edge of tile */
  172.  
  173. RGBvals BlurColour;  /* Colour to fade tiles to when nearing horizon */
  174.  
  175.  
  176. int XPos, YPos;  /* Position of observer relative to a tile */
  177. int Angle;  /* Direction observer is facing */
  178.  
  179. int TimerDelay = 0;  /* Seconds demo runs for, or no timer if zero */
  180. int StopMessage = 0;  /* Flag: suppress display of end credits */
  181. char * PicFile = NULL;  /* Name of file to load for tile image */
  182.  
  183.  
  184.  
  185.  
  186.  
  187. /* CODE STARTS HERE */
  188.  
  189. enum { RET_ESCAPE = 1, RET_TIME = 0 };
  190.  
  191. int main(int argc, char * argv[]) {
  192.  
  193.     int ret_code;
  194.  
  195.     randomize();
  196.  
  197.     CommandArguments(argc, argv);
  198.     ChooseColours();
  199.  
  200.     AllocateMemory();
  201.  
  202.     MakeDistances();
  203.     MakeBlurs();
  204.  
  205.     ScreenOn();
  206.     GoBlack();
  207.  
  208.     PaintSky();
  209.     if ( PicFile == NULL || LoadTile(PicFile) == 0 ) PaintTile();
  210.     BlurPalette();
  211.  
  212.     XPos = random(256);
  213.     YPos = random(256);
  214.     Angle = random(ANGLES);
  215.     DisplayMatrix(Angle, XPos, YPos);
  216.  
  217.     SetPalette(Palette, 0, 256);
  218.  
  219.     ret_code = Animate();
  220.  
  221.     ScreenOff();
  222.  
  223.     FreeMemory();
  224.  
  225.     if ( ! StopMessage ) Message();
  226.     return ret_code;
  227. }
  228.  
  229.  
  230.  
  231. /* Run the animation until either a key is pressed (return RET_ESCAPE) */
  232. /*   or the time TimerDelay runs out (return RET_TIME)                 */
  233.  
  234. int Animate() {
  235.     time_t start_time = time(NULL);
  236.  
  237.     for (;;) {
  238.  
  239.         MoveMatrix();
  240.         DisplayMatrix(Angle, XPos, YPos);
  241.  
  242.         if ( kbhit() ) {
  243.             while ( kbhit() ) getch();
  244.             return RET_ESCAPE;
  245.         }
  246.  
  247.         if ( TimerDelay && (time(NULL) - start_time) > TimerDelay ) {
  248.             return RET_TIME;
  249.         }
  250.  
  251.     }
  252. }
  253.  
  254.  
  255.  
  256. /* Move the matrix position [XPos, YPos, Angle] (global vars) by one step  */
  257. /* Angular velocity swings left then right (as a sine wave) holding on at  */
  258. /*   its peak value for a random time                                      */
  259. /* Point moves in the direction of Angle with speed (both forwards and     */
  260. /*   backwards) varying randomly                                           */
  261. /* Additional 'drift' motion occurs in a direction perpendicular to Angle  */
  262.  
  263. #define MAX_ANGVEL 7
  264. #define MAX_SPEED 50
  265. #define DRIFT_STRENGTH 0.7
  266.  
  267. void MoveMatrix() {
  268.  
  269.     static int angvel, angvel_sign;
  270.     static int peak_angvel = 0;
  271.     static int cycle_step, cycle_length, peak_hold;
  272.  
  273.     static int speed = MAX_SPEED/3, speed_dest = MAX_SPEED/3;
  274.     static int speed_hold = 0;
  275.  
  276.     static int drift;
  277.     static int drift_step = 0, drift_length = 0;
  278.     static float drift_peak;
  279.  
  280.   /* Change viewing angle */
  281.  
  282.     if ( peak_angvel == 0 ) {
  283.         peak_angvel = random(3*MAX_ANGVEL/4 + 1) + MAX_ANGVEL/4;
  284.         angvel_sign = 2*random(2) - 1;
  285.         cycle_length = (2 + peak_angvel + random(10)) * 2;
  286.         cycle_step = 0;
  287.         peak_hold = random(150) + 15*(MAX_ANGVEL-peak_angvel);
  288.     }
  289.  
  290.     if ( cycle_step > cycle_length ) {
  291.         peak_angvel = random(3*MAX_ANGVEL/4 + 1) + MAX_ANGVEL/4;
  292.         angvel_sign = -angvel_sign;
  293.         cycle_length = (2 + peak_angvel + random(10)) * 2;
  294.         cycle_step = 0;
  295.         peak_hold = random(150) + 15*(MAX_ANGVEL-peak_angvel);
  296.     }
  297.  
  298.     if ( cycle_step == cycle_length ) angvel = 0;
  299.     else angvel = angvel_sign *
  300.                (peak_angvel * Sin( (cycle_step*ANGLES/2) / cycle_length ) + 1);
  301.  
  302.     if ( cycle_step == cycle_length/2 && peak_hold > 0 ) peak_hold--;
  303.     else cycle_step++;
  304.  
  305.     Angle = ( Angle + angvel ) & (ANGLES-1);
  306.  
  307.   /* Move point in direction of Angle */
  308.  
  309.     if ( speed == speed_dest ) {
  310.         if ( speed_hold > 0 ) speed_hold--;
  311.         else {
  312.             speed_dest = random(2*MAX_SPEED/3 + 1) + MAX_SPEED/3;
  313.             speed_dest *= 2*random(2) - 1;
  314.             speed_hold = random(40) + 10;
  315.         }
  316.     }
  317.  
  318.     if ( speed < speed_dest ) speed++;
  319.     if ( speed > speed_dest ) speed--;
  320.  
  321.     XPos = ( XPos + (int)(speed*Cos(Angle)) ) & 255;
  322.     YPos = ( YPos + (int)(speed*Sin(Angle)) ) & 255;
  323.  
  324.   /* Drift perpendicular to Angle */
  325.  
  326.     if ( drift_step == drift_length ) {
  327.         drift_step = 0;
  328.         drift_length = 25 + random(75);
  329.         drift_peak = DRIFT_STRENGTH * ( random(21) - 10 ) / 10.0;
  330.     } else {
  331.         drift_step++;
  332.     }
  333.  
  334.     drift = drift_peak*speed * Sin( (ANGLES * drift_step) / drift_length );
  335.  
  336.     XPos = ( XPos - (int)(drift*Sin(Angle)) ) & 255;
  337.     YPos = ( YPos + (int)(drift*Cos(Angle)) ) & 255;
  338. }
  339.  
  340.  
  341.  
  342. /* Draw sky pattern on top half of screen and set palette values 0-63 */
  343. /* Colour of sky determined by SkyColour structure and DullSky flag   */
  344.  
  345. void PaintSky() {
  346.     int col1, col2, col3, col4;
  347.     char far * scr_ptr;
  348.     char far * scr_ptr2;
  349.     int i, j, k;
  350.  
  351.   /* Paint the sky */
  352.     if ( DullSky ) {
  353.  
  354.       /* Sky brightens slowly */
  355.         scr_ptr = MK_FP(0xA000, 0);
  356.         for ( j = 0 ; j < 320 ; j++ ) {
  357.             col1 = ( random(7) == 0 );
  358.             col2 = ( random(8) < 3 );
  359.             col3 = ( random(8) >= 3 );
  360.             col4 = ( random(7) != 0 );
  361.             scr_ptr2 = scr_ptr;
  362.             k = j;
  363.             for ( i = 0 ; i < 25 ; i++ ) {
  364.                 *(scr_ptr2+k) = col1+i;
  365.                 *(scr_ptr2+320+k) = col2+i;
  366.                 *(scr_ptr2+640+k) = col3+i;
  367.                 *(scr_ptr2+960+k) = col4+i;
  368.                 scr_ptr2 += 1280;
  369.                 k += 37;
  370.                 if ( k >= 320 ) k -= 320;
  371.             }
  372.         }
  373.  
  374.     } else {
  375.  
  376.       /* Sky brightens quickly */
  377.         scr_ptr = MK_FP(0xA000, 0);
  378.         for ( j = 0 ; j < 320 ; j++ ) {
  379.             col1 = ( random(3) == 0 );
  380.             col2 = ( random(3) != 0 );
  381.             scr_ptr2 = scr_ptr;
  382.             k = j;
  383.             for ( i = 0 ; i < 50 ; i++ ) {
  384.                 *(scr_ptr2+k) = col1+i;
  385.                 *(scr_ptr2+320+k) = col2+i;
  386.                 scr_ptr2 += 640;
  387.                 k += 37;
  388.                 if ( k >= 320 ) k -= 320;
  389.             }
  390.         }
  391.  
  392.     }
  393.  
  394.   /* Choose palette colours 0 to 63 */
  395.     for ( i = 0 ; i < 64 ; i++ ) {
  396.         Palette[i].red = (SkyColour.red * i)/63;
  397.         Palette[i].green = (SkyColour.green * i)/63;
  398.         Palette[i].blue = (SkyColour.blue * i)/63;
  399.     }
  400.  
  401. }
  402.  
  403.  
  404.  
  405. /* Draw simple image on tile using colours 0-31               */
  406. /* Set up first (unblurred) section of palette, colours 64-95 */
  407. /* Pick colour to blur to when approaching horizon            */
  408.  
  409. void PaintTile() {
  410.     char far * topl, far * topr, far * left, far * lefb;
  411.     unsigned char col;
  412.     int i, j;
  413.  
  414.   /* Draw piccy on Tile */
  415.     col = 0;
  416.     for ( j=31 ; j >= 0 ; j-- ) {
  417.         topl = (char far *) Tile + 4*j;
  418.         topr = (char far *) Tile + 252 - 4*j;
  419.         left = (char far *) Tile + ((4*j)<<8);
  420.         lefb = (char far *) Tile + ((252-4*j)<<8);
  421.         for ( i = 0 ; i < 256 ; i++ ) {
  422.             *(topl) = *(topl+1) = *(topl+2) = *(topl+3)
  423.                 = *(topr) = *(topr+1) = *(topr+2) = *(topr+3) =  col;
  424.             *(left) = *(left+256) = *(left+512) = *(left+768)
  425.                 = *(lefb) = *(lefb+256) = *(lefb+512) = *(lefb+768) = col;
  426.             topl += 256;
  427.             topr += 256;
  428.             left += 1;
  429.             lefb += 1;
  430.         }
  431.         col++;
  432.     }
  433.  
  434.   /* Choose palette colours 64 to 95 */
  435.     for ( i = 0 ; i < 32 ; i++ ) {
  436.         Palette[64+i].red = TileColour2.red +
  437.                 ((TileColour1.red - TileColour2.red) * i) / 31;
  438.         Palette[64+i].green = TileColour2.green +
  439.                 ((TileColour1.green - TileColour2.green) * i) / 31;
  440.         Palette[64+i].blue = TileColour2.blue +
  441.                 ((TileColour1.blue - TileColour2.blue) * i) / 31;
  442.     }
  443.  
  444.   /* Set colour to blur to */
  445.     BlurColour.red = (TileColour1.red + TileColour2.red)/2;
  446.     BlurColour.green = (TileColour1.green + TileColour2.green)/2;
  447.     BlurColour.blue = (TileColour1.blue + TileColour2.blue)/2;
  448. }
  449.  
  450.  
  451.  
  452. /* Load a tile image from a file                         */
  453. /* fname.BIN is a 256*256 bitmap using colours 0-31 only */
  454. /* fname.PAL is a 32 value palette for the image         */
  455. /* Sets BlurColour to average shade in palette           */
  456.  
  457. int LoadTile(char * fname) {
  458.     char * file_name;
  459.     int handle;
  460.     unsigned nread;
  461.     char far * t_ptr = (char far *) Tile;
  462.     int i;
  463.     int r,g,b;
  464.  
  465.     file_name = (char *) malloc(strlen(fname)+4);
  466.     strcpy(file_name, fname);
  467.     strcat(file_name, ".BIN");
  468.     if ( _dos_open(file_name, O_RDONLY, &handle) != 0 ) return 0;
  469.  
  470.     if ( _dos_read(handle, (void far *)t_ptr, 32768L, &nread) != 0 ) return 0;
  471.     if ( _dos_read(handle, (void far *)(t_ptr+32768L), 32768L, &nread)
  472.             != 0 ) return 0;
  473.  
  474.     _dos_close(handle);
  475.  
  476.     strcpy(file_name+strlen(file_name)-4, ".PAL");
  477.     if ( _dos_open(file_name, O_RDONLY, &handle) != 0 ) return 0;
  478.  
  479.     if ( _dos_read(handle, (void far *)(Palette+64), 3*32L, &nread)
  480.             != 0 ) return 0;
  481.  
  482.     _dos_close(handle);
  483.  
  484.     free(file_name);
  485.  
  486.     r = g = b = 0;
  487.     for ( i = 0 ; i < 32 ; i++ ) {
  488.         r += Palette[64+i].red;
  489.         g += Palette[64+i].green;
  490.         b += Palette[64+i].blue;
  491.     }
  492.     BlurColour.red = r/32;
  493.     BlurColour.green = g/32;
  494.     BlurColour.blue = b/32;
  495.  
  496.     return 1;
  497. }
  498.  
  499.  
  500.  
  501. /* Fill in blurred sections of palette                                      */
  502. /* Colour ranges 96-127, 128-159, ..., 224-255 are the same as range 64-95  */
  503. /*  but faded progressively closer to the colour BlurColour                 */
  504. /* These blurred colours are used to fade the tile pattern near the horizon */
  505.  
  506. void BlurPalette() {
  507.     int i, j;
  508.     int c;
  509.  
  510.     for ( i = 3 ; i < 8 ; i++ ) {
  511.         j = (i-2);
  512.         if ( j > 2 ) j = j*2 - 2;
  513.         for ( c = 0 ; c < 32 ; c++ ) {
  514.             Palette[c+32*i].red = Palette[c+64].red +
  515.                     ((BlurColour.red - Palette[c+64].red) * j)/9;
  516.             Palette[c+32*i].green = Palette[c+64].green +
  517.                     ((BlurColour.green - Palette[c+64].green) * j)/9;
  518.             Palette[c+32*i].blue = Palette[c+64].blue +
  519.                     ((BlurColour.blue - Palette[c+64].blue) * j)/9;
  520.         }
  521.     }
  522.  
  523. }
  524.  
  525.  
  526.  
  527. /* All palette colours set to black, Palette zeroed */
  528.  
  529. void GoBlack() {
  530.     int i;
  531.     for ( i = 0 ; i < 256 ; i++ )
  532.         Palette[i].red = Palette[i].green = Palette[i].blue = 0;
  533.     SetPalette(Palette, 0, 256);
  534. }
  535.  
  536.  
  537.  
  538. /* Display exit message */
  539.  
  540. void Message() {
  541.     puts(
  542.       "MATRIX DEMO \n"
  543.       "Simon Hern (22 Harrington Drive, Bedford, MK41 8DB, England)\n"
  544.       "July 1990, August 1993, September 1994, June 1995\n\n"
  545.       "Command line options:\n"
  546.       "  /s - Suppress this message\n"
  547.       "  /t:<delay> - Time-out after <delay> seconds (default 120)\n"
  548.       "  /0:<col> - Select sky colour (/0 for list of colours)\n"
  549.       "  /1:<col1>;<col2> - Select tile colours (/1 for list of colours)\n"
  550.       "  /p:<fname> - Load tile image from file (/p for details)"
  551.     );
  552. }
  553.  
  554.  
  555.  
  556. /* Terminate with error message */
  557.  
  558. void Error(char * comment) {
  559.     ScreenOff();
  560.     printf("Error:  %s\n", comment);
  561.     exit(1);
  562. }
  563.  
  564.  
  565.  
  566. /* Allocate memory for the arrays Tile, ScrBuffer, Distances, Blurs, Palette */
  567. /* The first three of these need to be aligned in memory, so a little extra  */
  568. /*  memory is allocated to them to make sure they fit the alignment          */
  569.  
  570. void AllocateMemory() {
  571.     unsigned seg, off;
  572.  
  573.   /* Tile: far, aligned to segment boundary */
  574.     Tile_alloc = (char far *) farmalloc(TILE_SIZE + 16);
  575.     if ( Tile_alloc == NULL ) Error("Insufficient memory for Tile array");
  576.     seg = FP_SEG(Tile_alloc) + (FP_OFF(Tile_alloc) >> 4) + 1;
  577.     Tile = (char far *) MK_FP(seg, 0);
  578.  
  579.   /* ScrBuffer: far, aligned to segment boundary */
  580.     ScrBuffer_alloc = (char far *) farmalloc(SCR_WIDTH*SCR_HEIGHT/2 + 16);
  581.     if ( ScrBuffer_alloc == NULL ) Error("Insufficient memory for ScrBuffer array");
  582.     seg = FP_SEG(ScrBuffer_alloc) + (FP_OFF(ScrBuffer_alloc) >> 4) + 1;
  583.     ScrBuffer = (char far *) MK_FP(seg, 0);
  584.  
  585.   /* Distances: near, aligned to word boundary */
  586.     Distances_alloc = (char *) malloc(sizeof(int)*SCR_HEIGHT/2 + 1);
  587.     if ( Distances_alloc == NULL ) Error("Insufficient memory for Distances array");
  588.     off = (unsigned) Distances_alloc;
  589.     Distances = (int *) ( off + (off&1) );
  590.  
  591.   /* Blurs: near, non-aligned */
  592.     Blurs = (unsigned char *) malloc(SCR_HEIGHT/2);
  593.     if ( Blurs == NULL ) Error("Insufficient memory for Blurs array");
  594.  
  595.   /* Palette: near, non-aligned */
  596.     Palette = (RGBvals *) malloc(256*sizeof(RGBvals));
  597.     if ( Palette == NULL ) Error("Insufficient memory for Palette array");
  598.  
  599. }
  600.  
  601.  
  602.  
  603. /* Release the memory allocated by AllocateMemory() */
  604.  
  605. void FreeMemory() {
  606.     farfree(Tile_alloc);
  607.     farfree(ScrBuffer_alloc);
  608.     free(Distances_alloc);
  609.     free(Blurs);
  610.     free(Palette);
  611. }
  612.  
  613.  
  614.  
  615. /* Generate the array of Distances                                         */
  616. /* There is one value (a signed int/word) for each line of the image       */
  617. /* The value is the distance of the middle point on the line from          */
  618. /*  the observer when projected down onto the plane of tiles               */
  619. /* The values for the top two lines are bigger than 16 bits will store -   */
  620. /*  arbitrary large numbers are used instead since they make no difference */
  621.  
  622. void MakeDistances() {
  623.     int i;
  624.     for ( i = 2 ; i < SCR_HEIGHT/2 ; i++ ) {
  625.         /* Viewer's eye is taken to be height SCR_HEIGHT/2 above the plane */
  626.         Distances[i] = ( VIEW_DIST * (long)SCR_HEIGHT / 2 ) / ( i + 0.5 );
  627.     }
  628.     Distances[0] = 32767;
  629.     Distances[1] = 28000;
  630. }
  631.  
  632.  
  633.  
  634. /* A Blur value is used for each line of the image on the screen         */
  635. /* The Blur is the top 3 bits of an 8 bit number (greater than 63)       */
  636. /*  and is added to the points in the tile image to select which part of */
  637. /*  the "blurred" palette is to be used                                  */
  638. /* The bottom line of the image is unblurred, the top line very blurred  */
  639.  
  640. void MakeBlurs() {
  641.     int i;
  642.     int v;
  643.     for ( i = 0 ; i < 100 ; i++ ) {
  644.         /* The formula here was created through lots of trial and error */
  645.         v = log( (double) 100.0 / (2+i+0.5) ) / log( (double) 2 );
  646.         if ( v > 5 ) v = 5;
  647.         Blurs[i] = ( 2 + v ) << 5;
  648.     }
  649. }
  650.  
  651.  
  652.  
  653. /* Parse the command line arguments */
  654. /* (Global variables updated)       */
  655.  
  656. #define TIMER_DEFAULT 120
  657.  
  658. char * fmessage = "No filename given\n\n"
  659.                   "  /p:<fname> - Load tile image from file\n"
  660.                   "  where <fname>.BIN is a 256*256 bitmap using colours 0-31,\n"
  661.                   "        <fname>.PAL is a 32 colour palette for the picture";
  662.  
  663. void CommandArguments(int argc, char * argv[]) {
  664.     int parm;
  665.     char * start, * end;
  666.     char err[80*25];  /* String for holding screen length error message */
  667.  
  668.     for ( parm = 1 ; parm < argc ; parm++ ) {
  669.         if ( argv[parm][0] == '/' || argv[parm][0] == '-' ) {
  670.             switch (argv[parm][1]) {
  671.  
  672.               /* "/t:delay" - set timer delay (in seconds) */
  673.               /*    0 for no timer, 120 by default         */
  674.               case 't':
  675.               case 'T':
  676.                 start = argv[parm] + 2;
  677.                 if ( *start == ':' ) start++;
  678.                 TimerDelay = TIMER_DEFAULT;
  679.                 if ( *start != '\0' ) {
  680.                     TimerDelay = atoi(start);
  681.                     if ( TimerDelay < 0 ) TimerDelay = 0;
  682.                 }
  683.                 break;
  684.  
  685.               /* "/s" - switch off end message */
  686.               case 's':
  687.               case 'S':
  688.                 StopMessage = 1;
  689.                 break;
  690.  
  691.               /* "/p:fname" - name file to load tile image from */
  692.               case 'p':
  693.               case 'P':
  694.                 start = argv[parm] + 2;
  695.                 if ( *start == ':' ) start++;
  696.                 PicFile = start;
  697.                 if ( *PicFile == '\0' ) Error(fmessage);
  698.                 break;
  699.  
  700.               /* "/0:colour" - choose sky colour (by colour name) */
  701.               /*    name prefix 'dark' specifies a dull sky       */
  702.               case '0':
  703.                 start = argv[parm]+2;
  704.                 if ( *start == ':' ) start++;
  705.                 if ( strnicmp(start, "dark", 4) == 0 ) {
  706.                     start += 4;
  707.                     DullSky = 1;
  708.                 } else DullSky = 0;
  709.                 end = ReadColour(&SkyColour, start);
  710.                 if ( *end != '\0' || end == start ) {
  711.                     sprintf(err, "Invalid sky colour selection  %s\n\n", argv[parm]);
  712.                     ListSkyColours(err + strlen(err));
  713.                     Error(err);
  714.                 }
  715.                 break;
  716.  
  717.               /* "/1:col1;col2" - choose tile colours (by colour name) */
  718.               case '1':
  719.                 start = argv[parm]+2;
  720.                 if ( *start == ':' ) start++;
  721.                 end = ReadColour(&TileColour1, start);
  722.                 if ( *end != ';' || end == start ) {
  723.                     sprintf(err, "Invalid tile colour selection  %s\n\n", argv[parm]);
  724.                     ListTileColours(err + strlen(err));
  725.                     Error(err);
  726.                 }
  727.                 start = end+1;
  728.                 end = ReadColour(&TileColour2, start);
  729.                 if ( *end != '\0' || end == start ) {
  730.                     sprintf(err, "Invalid tile colour selection  %s\n\n", argv[parm]);
  731.                     ListTileColours(err + strlen(err));
  732.                     Error(err);
  733.                 }
  734.                 break;
  735.  
  736.               default:
  737.                 sprintf(err, "Unrecognized command line argument %s", argv[parm]);
  738.                 Error(err);
  739.                 break;
  740.  
  741.             }
  742.         } else {
  743.             sprintf(err, "Unrecognized command line argument %s", argv[parm]);
  744.             Error(err);
  745.         }
  746.     }
  747.  
  748. }
  749.  
  750.  
  751.  
  752. /* If not already selected, choose tile and sky colours      */
  753. /* (Colour schemes used are defined in 'ScreenColour' table) */
  754.  
  755. void ChooseColours() {
  756.     int colour_set;
  757.     char * start, * end;
  758.  
  759.     colour_set = random(101)%COLOUR_CHOICES;
  760.  
  761.     if ( TileColour1.red == -1 ) {
  762.         start = ScreenColours[colour_set].tile1;
  763.         end = ReadColour(&TileColour1, start);
  764.         if ( *end != '\0' || end == start ) Error("Bad colour defined in ScreenColours table");
  765.     }
  766.  
  767.     if ( TileColour2.red == -1 ) {
  768.         start = ScreenColours[colour_set].tile2;
  769.         end = ReadColour(&TileColour2, start);
  770.         if ( *end != '\0' || end == start ) Error("Bad colour defined in ScreenColours table");
  771.     }
  772.  
  773.     if ( SkyColour.red == -1 ) {
  774.         start = ScreenColours[colour_set].sky;
  775.         if ( strnicmp(start, "dark", 4) == 0 ) {
  776.             start += 4;
  777.             DullSky = 1;
  778.         } else DullSky = 0;
  779.         end = ReadColour(&SkyColour, start);
  780.         if ( *end != '\0' || end == start ) Error("Bad colour defined in ScreenColours table");
  781.     }
  782. }
  783.  
  784.  
  785.  
  786. /* Set 'dest' to colour named in string                */
  787. /* Return pointer to end of string if a match is found */
  788. /* (Names and values are defined in 'Colours' table)   */
  789.  
  790. char * ReadColour(RGBvals * dest, char * str) {
  791.     int i;
  792.  
  793.     for ( i = 0 ; i < COLOURS ; i ++ ) {
  794.         if ( strnicmp(str, Colours[i].name, strlen(Colours[i].name)) == 0 ) {
  795.             dest->red = Colours[i].colour.red;
  796.             dest->green = Colours[i].colour.green;
  797.             dest->blue = Colours[i].colour.blue;
  798.             return str + strlen(Colours[i].name);
  799.         }
  800.     }
  801.  
  802.     return str;
  803. }
  804.  
  805.  
  806.  
  807. /* Add to end of string some text on how to select the sky colour */
  808.  
  809. void ListSkyColours(char * dest) {
  810.     int i, c=0;
  811.  
  812.     strcat(dest, "Set sky colour:  \"/0:<colour>\"\n");
  813.     strcat(dest, "\nColours:\n");
  814.  
  815.     for ( i = 0 ; i < COLOURS ; i++ ) {
  816.         if ( strnicmp(Colours[i].name, "dark", 4) != 0 ) {
  817.             if ( c > 60 ) {
  818.                 strcat(dest, "\n");
  819.                 c = 0;
  820.             }
  821.             strcat(dest, "    ");
  822.             strcat(dest, Colours[i].name);
  823.             c += strlen(Colours[i].name) + 4;
  824.             if ( c > 60 ) {
  825.                 strcat(dest, "\n");
  826.                 c = 0;
  827.             }
  828.             strcat(dest, "    dark");
  829.             strcat(dest, Colours[i].name);
  830.             c += strlen(Colours[i].name) + 8;
  831.         }
  832.     }
  833.  
  834.     strcat(dest, "\n");
  835. }
  836.  
  837.  
  838.  
  839. /* Add to end of string some text on how to select the tile colours */
  840.  
  841. void ListTileColours(char * dest) {
  842.     int i, c=0;
  843.  
  844.     strcat(dest, "Set tile colours:  \"/1:<outside>;<inside>\"\n");
  845.     strcat(dest, "\nColours:\n");
  846.  
  847.     for ( i = 0 ; i < COLOURS ; i++ ) {
  848.         if ( c > 60 ) {
  849.             strcat(dest, "\n");
  850.             c = 0;
  851.         }
  852.         strcat(dest, "    ");
  853.         strcat(dest, Colours[i].name);
  854.         c += strlen(Colours[i].name) + 4;
  855.     }
  856.  
  857.     strcat(dest, "\n");
  858. }
  859.  
  860.  
  861.  
  862. /* Fast sine calculation using precalculated table  */
  863. /* Angles scaled from 0 to (ANGLES-1) around circle */
  864.  
  865. float Sin(int a) {
  866.     a = a & (ANGLES-1);
  867.     return ( (float)AngleSines[a] / 32767.0 );
  868. }
  869.  
  870.  
  871.  
  872. /* Fast cosine calculation using precalculated table */
  873. /* Angles scaled from 0 to (ANGLES-1) around circle  */
  874.  
  875. float Cos(int a) {
  876.     a = ( a + ANGLES/4 ) & (ANGLES-1);
  877.     return ( (float)AngleSines[a] / 32767.0 );
  878. }
  879.  
  880.  
  881.  
  882.